#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>
#define TNUM 5
//pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; // pthread_mutex_t 就是原生线程库提供的一个数据类型.静态分配
// 如果多线程访问同一个全局变量，并对它进行数据计算，多线程会互相影响吗？
// 加锁保护：加锁的时候，一定要保证加锁的粒度，越小越好！！
// pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; // pthread_mutex_t 就是原生线程库提供的一个数据类型

// 加锁就是串行执行了吗？加锁了之后，线程在临界区中，是否会切换，会有问题吗？原子性的体现
// 加锁了之后，线程在临界区中，是否会切换，会有问题吗? 
// 会切换，不会！第一次理解：虽然被切换了，但是你是持有锁被切换的, 所以其他抢票线程要执行临界区代码，
// 也必须先申请锁，锁它是无法申请成功的，所以，也不会让其他线程进入临界区，就保证了临界区中数据一致性！
// 我是一个线程，我不申请锁，就是单纯的访问临界资源！-- 错误的编码方式
// 在没有持有锁的线程看来，对我最有意义的情况只有两种：1. 线程1没有持有锁(什么都没做) 2. 线程1释放锁(做完)，此时我可以申请锁！
// 加锁就是串行执行了吗？ 是的，执行临界区代码一定是串行的！
// 要访问临界资源，每一个线程都必须现申请锁，每一个线程都必须先看到同一把锁&&访问它，锁本身是不是就是一种共享资源？
// 谁来保证锁的安全呢？？所以，为了保证锁的安全，申请和释放锁，必须是 原子的！！！自己保证
// 如何保证？？锁是如何实现的？
int tickets = 10000; // 在并发访问的时候，导致了我们数据不一致的问题！临界资源
//__thread int tickets=5;
//pthread_mutex_t* mtx;
class Mutex
{
    public:
    Mutex()
    {
        pthread_mutex_init(&_pmtx,nullptr);
    }
    void lock()
    {
        pthread_mutex_lock(&_pmtx);
    }
    void unlock()
    {
        pthread_mutex_unlock(&_pmtx);
    }
    ~Mutex()
    {
        pthread_mutex_destroy(&_pmtx);
    }
private:
    pthread_mutex_t _pmtx;
};

// class ThreadData
// {
// public:
//     ThreadData(std::string& name,pthread_mutex_t* pmtx)
//     :_name(name)
//     ,_pmtx(pmtx)
//     {}
// public:
//     std::string _name;
//     pthread_mutex_t* _pmtx;//互斥锁
// };

// void* getTickets(void* args)
// {
    

//     //(void)args;
    
//     ThreadData* td=(ThreadData*)(args);
//     //Mutex mut=td->_pmtx;
//     while(tickets)
//     {
//        // pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
//         //pthread_mutex_lock(td->_pmtx);//加锁
//         //td->_pmtx.lock();
//         if(tickets > 0)
//         {
            
//             //usleep(1000);
//             sleep(1);
//             printf("%p: %d\n", pthread_self(), tickets);
//             pthread_mutex_unlock(td->_pmtx);//解锁
//             tickets--;
//             //pthread_mutex_unlock(&mtx);
            
//         }
//         else
//         {
//             pthread_mutex_unlock(td->_pmtx);   
//             break;
//         }
//     }
//     return nullptr;
// }
//动态分配
// int main()
// {

//     //ThreadData td;
//     pthread_mutex_t mtx;
    
//     pthread_t tid[TNUM];
//     pthread_mutex_init(&mtx,nullptr);
//     for(int i = 1; i <= TNUM; i++)
//     {
//         std::string name = "thread ";
//         name += std::to_string(i+1);
//         ThreadData *td = new ThreadData(name, &mtx);
//         pthread_create(tid + i, nullptr, getTickets, (void*)td);
//     }

//     for(int i=1;i<=TNUM;i++)
//     {
//         pthread_join(tid[i],nullptr);
//     }

//     pthread_mutex_destroy(&mtx);
//     return 0;
// }


//静态分配
// int main()
// {
//     pthread_t tid1,tid2,tid3,tid4;
//     //std::string name = "thread ";
//     //name += std::to_string(i+1);
//     //ThreadData *td = new ThreadData(name, &mtx);
//     pthread_create(&tid1,nullptr,getTickets,(void*)"tickets one");
//     pthread_create(&tid2,nullptr,getTickets,(void*)"tickets two");
//     pthread_create(&tid3,nullptr,getTickets,(void*)"tickets three");
//     pthread_create(&tid4,nullptr,getTickets,(void*)"tickets four");


//     pthread_join(tid1,nullptr);
//     pthread_join(tid2,nullptr);
//     pthread_join(tid3,nullptr);
//     pthread_join(tid4,nullptr);

//     return 0;
// }

typedef void (*func_t)(const std::string &name,pthread_mutex_t *pmtx, pthread_cond_t *pcond);
volatile bool quit = false;

struct ThreadData
{
public:  
    ThreadData(const std::string &name, func_t func, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
    :_name(name), _func(func), _pmtx(pmtx), _pcond(pcond)
    {}

public:
    std::string _name;
    func_t _func;
    pthread_mutex_t *_pmtx;//线程互斥
    pthread_cond_t *_pcond;//线程唤醒
};

void func1(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while(!quit)
    {
        // wait一定要在加锁和解锁之间进行wait！
        // v2: 
        pthread_mutex_lock(pmtx);
        // if(临界资源是否就绪-- 否) pthread_cond_wait
        pthread_cond_wait(pcond, pmtx); //默认该线程在执行的时候，wait代码被执行，当前线程会被立即被阻塞
        std::cout << name << " running -- 播放" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void func2(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while(!quit)
    {
        // wait一定要在加锁和解锁之间进行wait！
        // v2: 
        pthread_mutex_lock(pmtx);
        // if(临界资源是否就绪-- 否) pthread_cond_wait
        pthread_cond_wait(pcond, pmtx); //默认该线程在执行的时候，wait代码被执行，当前线程会被立即被阻塞
        std::cout << name << " running -- 下载" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}
void func3(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while(!quit)
    {
        // wait一定要在加锁和解锁之间进行wait！
        // v2: 
        pthread_mutex_lock(pmtx);
        // if(临界资源是否就绪-- 否) pthread_cond_wait
        pthread_cond_wait(pcond, pmtx); //默认该线程在执行的时候，wait代码被执行，当前线程会被立即被阻塞
        std::cout << name << " running -- 暂停" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void func4(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while(!quit)
    {
        // wait一定要在加锁和解锁之间进行wait！
        // v2: 
        pthread_mutex_lock(pmtx);
        // if(临界资源是否就绪-- 否) pthread_cond_wait
        pthread_cond_wait(pcond, pmtx); //默认该线程在执行的时候，wait代码被执行，当前线程会被立即被阻塞
        std::cout << name << " running -- 继续" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void func5(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while(!quit)
    {
        // wait一定要在加锁和解锁之间进行wait！
        // v2: 
        pthread_mutex_lock(pmtx);
        // if(临界资源是否就绪-- 否) pthread_cond_wait
        pthread_cond_wait(pcond, pmtx); //默认该线程在执行的时候，wait代码被执行，当前线程会被立即被阻塞
        std::cout << name << " running -- 结束" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}
void *Entry(void *args)
{
    ThreadData *td = (ThreadData*)args; //td在每一个线程自己私有的栈空间中保存
    td->_func(td->_name, td->_pmtx, td->_pcond); // 它是一个函数，调用完成就要返回！
    delete td;
    return nullptr;
}
int main()
{
    pthread_mutex_t mtx;//线程互斥
    pthread_cond_t cond;//唤醒线程
    pthread_mutex_init(&mtx, nullptr);//初始化
    pthread_cond_init(&cond, nullptr);

     pthread_t tids[TNUM];
    func_t funcs[TNUM] = {func1, func2, func3, func4};
    for(int i=0;i<TNUM;i++)
    {
        std::string name="Thread ";
        name+="func"+i;
        ThreadData *td = new ThreadData(name, funcs[i], &mtx, &cond);
        pthread_create(tids+i,nullptr,Entry,(void*)td);
    }
   

    sleep(5);

    // ctrl new thread
    int cnt = 10;
    while(cnt)
    {
        std::cout << "resume thread run code ...." << cnt-- << std::endl;
        pthread_cond_signal(&cond);
        // pthread_cond_broadcast(&cond);
        sleep(1);
    }

    std::cout << "ctrl done" << std::endl;
    quit = true;
    pthread_cond_broadcast(&cond);

    for(int i = 0; i < TNUM; i++)
    {
        pthread_join(tids[i], nullptr);
        std::cout << "thread: " << tids[i] << "quit" << std::endl;
    }


    for(int i=0;i<TNUM;i++)
    {
        pthread_join(tids[i],nullptr);

    }
    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}